package com.kye.express.business.deposit.fragment;

import android.databinding.DataBindingUtil;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.jakewharton.rxbinding2.view.RxView;
import com.kye.base.DebounceObservableTransformer;
import com.kye.base.Logger;
import com.kye.base.utils.DateUtils;
import com.kye.base.utils.NetworkMonitorUtils;
import com.kye.express.R;
import com.kye.express.business.base.BaseAppCompatFragment;
import com.kye.express.business.deposit.model.DepositConsumptionDateModel;
import com.kye.express.business.deposit.model.EventBusMsgModel;
import com.kye.express.business.deposit.presenter.DepositConsumptionContract;
import com.kye.express.business.deposit.viewholder.DepositConsumptionViewBinder;
import com.kye.express.business.deposit.viewholder.DepositConsumptionDateViewBinder;
import com.kye.express.databinding.FragmentDepositConsumptionBinding;
import com.kye.express.view.ToastManager;
import com.kye.express.view.reclyerview.RecycleViewDivider;
import com.kye.model.bean.OpenApiResult;
import com.kye.model.bean.deposit.ResultDepositDetailedBean;
import com.kye.model.bean.user.User;
import com.kye.model.constant.Constants;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadmoreListener;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import java.util.Calendar;
import java.util.Date;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import me.drakeet.multitype.Items;
import me.drakeet.multitype.MultiTypeAdapter;

/**
 * 预存运费-消费记录Fragment
 * <p>
 * Created by SkyYu on 2018/1/17
 */
public class DepositConsumptionFragment extends BaseAppCompatFragment implements DepositConsumptionContract.DepositConsumptionView, DepositConsumptionDateViewBinder.OnTabLayoutListener {

    private FragmentDepositConsumptionBinding mBinding;
    private DepositConsumptionContract.DepositConsumptionPresenter mPresenter;
    private MultiTypeAdapter mAdapter;

    private String phone;
    private String companyName;
    private int pageSize = Constants.PAGE_SIZE;
    public int currentPageIndex = 1;
    private String dateFrom;
    private String dateTo;

    public static DepositConsumptionFragment newInstance() {
        return new DepositConsumptionFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_deposit_consumption, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initView(view);
        initData();
        initEvent();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (null != mPresenter) {
            mPresenter.unbind();
        }
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

    private void initView(View view) {
        initBinding(view);
        initPresenter();
    }

    private void initBinding(View view) {
        mBinding = DataBindingUtil.bind(view);
    }

    private void initPresenter() {
        mPresenter = new DepositConsumptionContract.DepositConsumptionPresenter(this);
        mPresenter.bind(this);
    }

    private void initData() {
        initAdapter();
    }

    private void initAdapter() {
        mAdapter = new MultiTypeAdapter();
        mAdapter.register(DepositConsumptionDateModel.class, new DepositConsumptionDateViewBinder(this));
        mAdapter.register(ResultDepositDetailedBean.DataBean.class, new DepositConsumptionViewBinder());

        Items data = new Items();
        data.add(getDefaultDate());
        mAdapter.setItems(data);

        mBinding.recyclerviewDepositConsumption.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
        mBinding.recyclerviewDepositConsumption.addItemDecoration(new RecycleViewDivider(getActivity(), LinearLayoutManager.HORIZONTAL, 3, getResources().getColor(R.color.grey_d9d9d9)));
        mBinding.recyclerviewDepositConsumption.setItemAnimator(new DefaultItemAnimator());
        mBinding.recyclerviewDepositConsumption.setAdapter(mAdapter);
    }

    private void initEvent() {
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }

        mBinding.refreshLayoutDepositConsumption.setOnRefreshLoadmoreListener(new OnRefreshLoadmoreListener() {
            @Override
            public void onRefresh(RefreshLayout refreshlayout) {
                request(false, false, true, false, phone, companyName, 1, pageSize, dateFrom, dateTo);
            }

            @Override
            public void onLoadmore(RefreshLayout refreshlayout) {
                request(false, false, false, true, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
            }
        });

        RxView.clicks(mBinding.llEmpty.btEmptyRetry)
                .compose(this.bindToLifecycleDestroy())
                .compose(new DebounceObservableTransformer<>())
                .subscribe((Object) -> {
                    mBinding.statusLayoutDepositConsumption.showLoadingView();
                    mPresenter.requestToDepositDetailed(false, false, true, false, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
                });
        RxView.clicks(mBinding.llErrorNet.btErrorNetRetry)
                .compose(this.bindToLifecycleDestroy())
                .compose(new DebounceObservableTransformer<>())
                .subscribe((Object) -> {
                    mBinding.statusLayoutDepositConsumption.showLoadingView();
                    mPresenter.requestToDepositDetailed(false, false, true, false, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
                });
        RxView.clicks(mBinding.llErrorServer.btErrorServerRetry)
                .compose(this.bindToLifecycleDestroy())
                .compose(new DebounceObservableTransformer<>())
                .subscribe((Object) -> {
                    mBinding.statusLayoutDepositConsumption.showLoadingView();
                    mPresenter.requestToDepositDetailed(false, false, true, false, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
                });
    }

    /**
     * 网络请求
     */
    private void request(boolean isAutoLoading, boolean isFirstIn, boolean isReFresh, boolean isLoadMore, String phone, String companyName, int pageIndex, int pageSize, String startTime, String endTime) {
        NetworkMonitorUtils.networkObservable(getActivity())
                .map((connectivity) -> {
                    NetworkInfo.State state = connectivity.getState();
                    switch (state) {
                        case CONNECTED:
                        case CONNECTING:
                            return true;
                        case DISCONNECTED:
                        case DISCONNECTING:
                            return false;
                        default:
                            return false;
                    }
                })
                .subscribe((Boolean) -> {
                    if (Boolean) {
                        mPresenter.refreshData(isAutoLoading, isFirstIn, isReFresh, isLoadMore, phone, companyName, pageIndex, pageSize, startTime, endTime);
                    } else {
                        mBinding.statusLayoutDepositConsumption.showErrorNetworkView();
                        ToastManager.show(getActivity(), getString(R.string.common_net_error));
                    }
                });
    }

    private void saveUserData(User user) {
        phone = user.getPhone();
        companyName = user.getLastAddress().get(0).getCompanyName();
    }

    /**
     * 订阅通知的回调函数，用于在充值页面充值后回到这个页面拉取最新数据
     */
    @Subscribe
    public void onEventMainThread(EventBusMsgModel msg) {
        if (msg.getType() == EventBusMsgModel.TYPE_REFRESH) {
            onConsumptionLoading();
        }
    }

    /**
     * 第一次加载数据的回调函数
     */
    @Override
    public void onUserLoad(User user) {
        saveUserData(user);
        request(false, true, false, false, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
    }

    /**
     * 重载加载的回调（用于后一天产生数据后然后回到这页开始自动更新请求拉取最新数据）
     */
    @Override
    public void onConsumptionLoading() {
        mBinding.refreshLayoutDepositConsumption.autoRefresh();
    }

    @Override
    public void onConsumptionComplete(boolean isLoadMore) {
        if (isLoadMore) {
            mBinding.refreshLayoutDepositConsumption.finishLoadmore();
        } else {
            mBinding.refreshLayoutDepositConsumption.finishRefresh();
        }
    }

    @Override
    public void onConsumptionSuccess(OpenApiResult<ResultDepositDetailedBean> bean, boolean isFirstIn, boolean isLoadMore) {
        if (bean != null) {
            if (bean.getCode() == Constants.ResponseCode_SUCCESS) {
                if (bean.getData().getData().size() > 0) {
                    mBinding.statusLayoutDepositConsumption.showContentView();
                    Items data = (Items) mAdapter.getItems();
                    if (!isLoadMore) {
                        data.clear();
                        data.add(getLatestDate());
                        data.addAll(bean.getData().getData());
                        mAdapter.setItems(data);
                        mAdapter.notifyDataSetChanged();
                    } else {
                        data.addAll(bean.getData().getData());
                        int start = bean.getData().getData().size();
                        mAdapter.notifyItemRangeChanged(start, data.size());
                    }
                } else {
                    if (isFirstIn) {
                        mBinding.statusLayoutDepositConsumption.getEmptyTextView();
                    } else {
                        ToastManager.show(getActivity(), getString(R.string.common_no_more_datas));
                    }
                }
                if(bean.getData().getData().size() < pageSize){
                    mBinding.refreshLayoutDepositConsumption.setEnableLoadmore(false);
                }
            } else {
                if (isLoadMore) {
                    mBinding.statusLayoutDepositConsumption.showContentView();
                    ToastManager.show(getActivity(), getString(R.string.common_no_more_datas));
                } else {
                    mBinding.statusLayoutDepositConsumption.showErrorServerView();
                    ToastManager.show(getActivity(), bean.getMsg());
                }
            }
        } else {
            Logger.d("DepositConsumptionFragment - onConsumptionSuccess - bean is null");
        }
    }

    @Override
    public void onConsumptionApiError(OpenApiResult<ResultDepositDetailedBean> result, int code, String msg) {
        mBinding.statusLayoutDepositConsumption.showErrorServerView();
        ToastManager.show(getActivity(), msg);
        Logger.d("DepositConsumptionFragment - onConsumptionApiError - result:" + result + ",code:" + code + ",msg:" + msg);
    }

    @Override
    public void onConsumptionOtherError(Throwable e) {
        ToastManager.show(getActivity(), getString(R.string.common_net_error));
        Logger.d("DepositConsumptionFragment - onConsumptionOtherError : " + e.getMessage());
        e.printStackTrace();
    }

    /**
     * 获取时间选择器的默认起始和结束时间（最近一个月）
     */
    @NonNull
    private DepositConsumptionDateModel getDefaultDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, -1);
        System.out.println(calendar.getTime());
        String lastDate = DateFormat.format("yyyy-MM-dd", calendar.getTime()).toString();
        String currentDate = DateFormat.format("yyyy-MM-dd", new Date()).toString();
        dateFrom = lastDate;
        dateTo = currentDate;
        DepositConsumptionDateModel dateModel = new DepositConsumptionDateModel();
        dateModel.dateFrom = lastDate;
        dateModel.dateTo = currentDate;
        return dateModel;
    }

    /**
     * 获取时间选择器的最新起始和结束时间
     */
    @NonNull
    private DepositConsumptionDateModel getLatestDate() {
        DepositConsumptionDateModel mTempDateModel = new DepositConsumptionDateModel();
        mTempDateModel.dateFrom = dateFrom;
        mTempDateModel.dateTo = dateTo;
        return mTempDateModel;
    }

    /**
     * 显示时间选择器对话框
     */
    private void showDateSelectDialog(@IntRange(from = 0, to = 1) final int type, final DepositConsumptionDateModel item) {
        int year;
        int monthOfYear;
        int dayOfMonth;
        Calendar calendar;
        if (type == Constants.QUERY_DATE_FROM) {
            calendar = DateUtils.dateStringToCalendarYMD(item.dateFrom);
        } else {
            calendar = DateUtils.dateStringToCalendarYMD(item.dateTo);
        }
        year = calendar.get(Calendar.YEAR);
        monthOfYear = calendar.get(Calendar.MONTH);
        dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        initDatePickerDialog(type, item, year, monthOfYear, dayOfMonth);
    }

    /**
     * 初始化时间选择对话框
     */
    private void initDatePickerDialog(@IntRange(from = 0, to = 1) int type, DepositConsumptionDateModel item, int year, int monthOfYear, int dayOfMonth) {
        DatePickerDialog datePickerDialog = DatePickerDialog.newInstance((DatePickerDialog view, int newest_year, int newest_monthOfYear, int newest_dayOfMonth) -> {
                    Calendar calendar2 = Calendar.getInstance();
                    calendar2.set(newest_year, newest_monthOfYear, newest_dayOfMonth);
                    switch (type) {
                        case Constants.QUERY_DATE_FROM:
                            onSelectQueryDateFrom(calendar2, item);
                            break;
                        case Constants.QUERY_DATE_TO:
                            onSelectQueryDateTo(calendar2, item);
                            break;
                    }
                },
                year,
                monthOfYear,
                dayOfMonth
        );
        datePickerDialog.vibrate(true);
        datePickerDialog.setVersion(DatePickerDialog.Version.VERSION_1);
        datePickerDialog.showYearPickerFirst(true);
        if (null != getActivity()) {
            datePickerDialog.show(getActivity().getFragmentManager(), Constants.DATE_PICKER_DIALOG);
        } else {
            Logger.d("getActivity() is null");
        }
    }

    /**
     * 时间选择器的起始时间的逻辑处理
     */
    private void onSelectQueryDateFrom(final Calendar calendarFrom, final DepositConsumptionDateModel item) {
        Observable.just(item.dateTo)
                .map((String s) ->
                        DateUtils.dateStringToCalendarYMD(s).getTime()
                )
                .subscribeOn(Schedulers.io())
                .map(DateUtils::dateToCalendar)
                .map((Calendar calendarTo) ->
                        DateUtils.testLeftLessOrEqualToRight(calendarFrom, calendarTo)
                )
                .observeOn(AndroidSchedulers.mainThread())
                .doOnNext((Boolean Boolean) -> {
                    if (Boolean) {
                        item.setDateFrom(DateUtils.getDateStringByDateYearMonthDay(calendarFrom.getTime()));
                        mAdapter.notifyItemChanged(0);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe((Boolean aBoolean) -> {
                    Logger.d("select date : " + aBoolean + " , date : " + DateUtils.getDateStringByDateYearMonthDay(calendarFrom.getTime()));
                    if (!aBoolean) {
                        ToastManager.show(getActivity(), "日期错误");
                    } else {
                        Logger.d("选择日期成功");
                    }
                });
    }

    /**
     * 时间选择器的结束时间的逻辑处理
     */
    private void onSelectQueryDateTo(final Calendar calendarTo, final DepositConsumptionDateModel item) {
        Observable.just(item.dateFrom)
                .map((String s) ->
                        DateUtils.dateStringToCalendarYMD(s).getTime()
                )
                .subscribeOn(Schedulers.io())
                .map(DateUtils::dateToCalendar)
                .map((Calendar calendarFrom) ->
                        DateUtils.testLeftLessOrEqualToRight(calendarFrom, calendarTo)
                )
                .observeOn(AndroidSchedulers.mainThread())
                .doOnNext((Boolean Boolean) -> {
                    if (Boolean) {
                        item.setDateTo(DateUtils.getDateStringByDateYearMonthDay(calendarTo.getTime()));
                        mAdapter.notifyItemChanged(0);
                    }
                })
                .subscribe((Boolean aBoolean) -> {
                    Logger.d("select date : " + aBoolean + " , date : " + DateUtils.getDateStringByDateYearMonthDay(calendarTo.getTime()));
                    if (!aBoolean) {
                        ToastManager.show(getActivity(), "日期错误");
                    } else {
                        Logger.d("选择日期成功");
                    }
                });
    }

    /**
     * 时间选择器的起始时间回调方法
     */
    @Override
    public void onSelectDateFrom(DepositConsumptionDateModel item) {
        showDateSelectDialog(0, item);
    }

    /**
     * 时间选择器的结束时间回调方法
     */
    @Override
    public void onSelectDateTo(DepositConsumptionDateModel item) {
        showDateSelectDialog(1, item);
    }

    /**
     * 时间选择器的查询回调方法
     */
    @Override
    public void onQueryConsumptionObtainData(DepositConsumptionDateModel item) {
        mBinding.statusLayoutDepositConsumption.showLoadingView();
        dateFrom = item.dateFrom;
        dateTo = item.dateTo;
        request(false, false, false, false, phone, companyName, currentPageIndex, pageSize, dateFrom, dateTo);
    }
}